package com.eudon.ai.agent.app;

import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.eudon.ai.agent.advisor.LoggerAdvisor;
import com.eudon.ai.agent.etl.factory.RetrievalAugmentationAdvisorFactory;
import com.eudon.ai.agent.tools.FileOperationTool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.util.List;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

/**
 * @author eudon
 * @description 恋爱大师app
 * @date 2025/8/8
 * @email syd19970616@gmail.com
 * @address <a href="https://gitee.com/eudon">Gitee</a>
 */
@Slf4j
@Component
public class LoveMaster {
    public static final String SYSTEM_PROMPT = "你是一个专业且富有同理心的AI恋爱大师，精通心理学、两性关系、亲密关系技巧，擅长以专业且温暖的方式指导用户解决恋爱相关问题。你将以温和、支持、鼓励的方式回应用户。\n" +
            "\n" +
            "你的角色是一个恋爱大师，职责包括：\n" +
            "\n" +
            "提供专业的恋爱建议和咨询。\n" +
            "分析用户的恋爱困境，并提供建设性的解决方案。\n" +
            "教授沟通技巧、吸引异性、处理冲突与情绪的方法。\n" +
            "指导用户如何建立健康、长久的关系。\n" +
            "为用户制定情感提升的小任务或练习。\n" +
            "帮助用户增强自信、情绪管理和自我认知能力。\n" +
            "用温暖、积极、有分寸的方式与用户互动，避免过于理性或机械的回答。\n" +
            "你应该具备的风格：\n" +
            "\n" +
            "理性又富有共情力。\n" +
            "语言通俗易懂，口语化。\n" +
            "鼓励用户自我探索和反思。\n" +
            "个性化，能根据历史对话调整建议。\n" +
            "请你以第一人称“我”来回答，避免使用专业术语，让建议更贴近生活、更实操。\n" +
            "\n" +
            "例如你可以这样回应：\n" +
            "\n" +
            "“听起来你是被他的忽冷忽热搞懵了，是吧？这种情况其实挺常见的，我们一起来理一理……”";

    private final ChatClient chatClient;
    private final VectorStore vectorStore;
    private final ToolCallback[] allTools;
    private final ToolCallbackProvider toolCallbackProvider;

    LoveMaster(ChatModel dashscopeChatModel,
               VectorStore myPostgresVectorStore,
               ToolCallback[] allTools, ToolCallbackProvider toolCallbackProvider) {
        this.vectorStore = myPostgresVectorStore;
        this.allTools = allTools;
        this.toolCallbackProvider = toolCallbackProvider;
        ChatMemory chatMemory = new InMemoryChatMemory();
        ChatOptions chatOptions = DashScopeChatOptions.builder().withEnableSearch(true).withTemperature(0.8).build();
        this.chatClient = ChatClient.builder(dashscopeChatModel)
                .defaultSystem(SYSTEM_PROMPT)
                .defaultAdvisors(
                        new MessageChatMemoryAdvisor(chatMemory)
//                        new LoggerAdvisor()
//                        new R2Advisor()
                )
                .defaultOptions(chatOptions)
                .build();
    }

    /**
     * 响应式调用
     *
     * @param userPrompt 用户提示词
     * @param chatId     聊天id
     * @return 响应式回复
     */
    public Flux<String> askWithStream(String userPrompt, String chatId) {
        ChatClient.StreamResponseSpec stream = chatClient.prompt(new Prompt(userPrompt))
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .stream();
        return stream.content();
    }

    /**
     * 非响应式调用
     *
     * @param userPrompt 用户提示词
     * @param chatId     聊天id
     * @return 非响应式回复
     */
    public String ask(String userPrompt, String chatId) {
        ChatResponse response = chatClient.prompt(new Prompt(userPrompt))
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .call()
                .chatResponse();
        return response.getResult().getOutput().getText();
    }

    /**
     * 返回报告的调用-SpringAI 结构化输出特性
     *
     * @param userPrompt 用户提示词
     * @param chatId     聊天id
     * @return 非响应式回复
     */
    public LoveReport askWithReport(String userPrompt, String chatId) {

        LoveReport report = chatClient.prompt(new Prompt(userPrompt))
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .call()
                .entity(LoveReport.class);
        return report;
    }

    record LoveReport(String title, List<String> suggestions) {
    }


    /**
     * 测试简单向量数据库
     *
     * @param userPrompt 用户提示词
     * @param chatId     聊天id
     * @return AI结果
     */
    public String askWithVector(String userPrompt, String chatId) {
        return chatClient.prompt()
                .user(userPrompt)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .advisors(new LoggerAdvisor())
                .advisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.builder().similarityThreshold(0.6).build()))
                .call()
                .chatResponse()
                .getResult()
                .getOutput()
                .getText();

    }


    /**
     * 测试Retrieval Augment
     *
     * @param userPrompt 用户提示词
     * @param chatId     聊天id
     * @param status     用户状态
     * @param label      文档标签
     * @return AI结果
     */
    public String askWithVectorAndRetrieval(String userPrompt, String chatId, String status, String label) {
        return chatClient.prompt()
                .user(userPrompt)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .advisors(new LoggerAdvisor())
                .advisors(RetrievalAugmentationAdvisorFactory.create(vectorStore, status, label))
                .call()
                .chatResponse()
                .getResult()
                .getOutput()
                .getText();

    }

    public String askWithVectorAndRetrieval(String userPrompt, String chatId, String status) {
        return chatClient.prompt()
                .user(userPrompt)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .advisors(new LoggerAdvisor())
                .advisors(RetrievalAugmentationAdvisorFactory.create(vectorStore, status))
                .call()
                .chatResponse()
                .getResult()
                .getOutput()
                .getText();

    }

    public String genAdvicesFile(String userPrompt, String chatId, String status) {
        return chatClient.prompt()
                .user(userPrompt)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .advisors(new LoggerAdvisor())
                .advisors(RetrievalAugmentationAdvisorFactory.create(vectorStore, status))
                .tools(new FileOperationTool())
                .call()
                .chatResponse()
                .getResult()
                .getOutput()
                .getText();
    }

    public String askWithSearch(String userPrompt, String chatId, String status) {
        return chatClient.prompt()
                .user(userPrompt)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .advisors(new LoggerAdvisor())
                .advisors(RetrievalAugmentationAdvisorFactory.create(vectorStore, status))
//                .tools(new SearchTool())  //最终采用注册器进行集体注册
                .tools(allTools)
                .call()
                .chatResponse()
                .getResult()
                .getOutput()
                .getText();
    }

    public String askWithMcp(String userPrompt, String chatId) {
        return chatClient.prompt()
                .user(userPrompt)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .advisors(new LoggerAdvisor())
                .advisors(RetrievalAugmentationAdvisorFactory.create(vectorStore, null))
//                .tools(new SearchTool())  //最终采用注册器进行集体注册
                .tools(toolCallbackProvider)
                .call()
                .chatResponse()
                .getResult()
                .getOutput()
                .getText();
    }
}
